﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Xml.Linq;
using EasyTCP;
using IServer.protobuf;
using Newtonsoft.Json;

namespace IServer
{
    class ChatRoom
    {


        public ChatRoom( )
        {
            var config = loadXmlConfig( "config.xml" );
            Console.WriteLine( $"loaded config:\nport: {config[1]}\nmaxLinkCount: {config[0]}" );

            EasyServer.bufferEncoder = Encoding.UTF8;
            EasyServer.onClientLinkCallback += onClientLink;
            EasyServer.onClientLogoutCallback += onClientLogout;
            EasyServer.onClientLostConnectionCallback += onClientLostConnection;
            EasyServer.onDataReceivedCallback += onDataReceived;


            EasyServer.Start( config[1], Convert.ToInt32( config[0] ) );
            Console.WriteLine( "Wait for the client to connect...." );
        }


        //ID:套接字
        Dictionary<string, Socket> clients = new Dictionary<string, Socket>( );
        #region 需要保存的数据
        //ID计数
        uint userIDCount = 0xffffff;
        //ID : 用户信息
        Dictionary<string, UserInfo> users = new Dictionary<string, UserInfo>( );
        //ID : OfflineInformation
        Dictionary<string, List<chat_data>> offLineInformation = new Dictionary<string, List<chat_data>>( );

        #endregion

        //当客户端连接成功
        void onClientLink( Socket newClient )
        {
            var ID = newClient.RemoteEndPoint.ToString( );
            Console.WriteLine( $"The new client connected successfully: {ID}" );
        }
        //客户端退出房间
        void onClientLogout( Socket client )
        {
            var ID = client.RemoteEndPoint.ToString( );
            if ( clients.ContainsKey( ID ) )
            {

                var msg = new MsgData( );
                msg.type = MsgType.Logout;
                msg.caller = ID;
                msg.data = JsonConvert.SerializeObject( users[ID] );

                clients.Remove( ID );
                users.Remove( ID );

                BroadcastMessage( msg );
            }

            Console.WriteLine( $"User exits the room: {ID}" );
        }
        //客户端掉线
        void onClientLostConnection( Socket client )
        {
            var ID = client.RemoteEndPoint.ToString( );
            var msg = new MsgData( );
            msg.type = MsgType.LostConnection;
            msg.caller = ID;
            BroadcastMessage( msg );

            Console.WriteLine( $"User lost connection: {ID}" );
        }
        //客户端掉线重连
        void onClientLostReconnect( Socket client )
        {
            var ID = client.RemoteEndPoint.ToString( );
            var msg = new MsgData( );
            msg.type = MsgType.LostReconnect;
            msg.caller = ID;
            BroadcastMessage( msg );

            Console.WriteLine( $"User lost reconnection: {ID}" );
        }
        //接收到客户端的数据
        bool onDataReceived( Socket target, string msgBuffer )
        {
            var msg = JsonConvert.DeserializeObject<MsgData>( msgBuffer );

#if DEBUG
            Console.WriteLine( $"Received data type: {msg.type.ToString( )}" );
#endif

            switch ( msg.type )
            {
                case MsgType.Register:
                    onClientRegister( target, msg );
                    break;
                case MsgType.Login:
                    onClientLogin( target, msg );
                    break;
                case MsgType.Logout:
                    onClientLogout( target );
                    return false;
                case MsgType.Chat:
                    onClient2Client( target, msg );
                    break;
                default:
                    break;
            }

            return true;
        }

        void offlineProc( string receiver, chat_data data )
        {

            List<chat_data> list = null;
            if ( !offLineInformation.TryGetValue( receiver, out list ) )
            {
                list = new List<chat_data>( );
                offLineInformation.Add( receiver, list );
            }

            list.Add( data );
        }


        //新账号注册
        void onClientRegister( Socket caller, MsgData msg )
        {
            //新客户端的信息
            var info = JsonConvert.DeserializeObject<UserInfo>( msg.data );
            info.ID = ( ++userIDCount ).ToString( );
            info.state = 2;


            //好友列表
            var data = new register_success_result( );

            data.info = info;
            if ( users.Count > 0 )
            {
                data.friends = new UserInfo[users.Count]; //世界的其他人信息
                users.Values.CopyTo( data.friends, 0 );
            }

            //发送好友列表信息
            var msg2 = new MsgData( );
            msg2.type = MsgType.Register;
            msg2.data = JsonConvert.SerializeObject( data );
            EasyServer.Send( caller, JsonConvert.SerializeObject( msg2 ) );



            //新注册的用户
            clients.Add( info.ID, caller );
            users.Add( info.ID, info );

            msg.caller = info.ID;
            msg.type = MsgType.FriendEvent;
            msg.data = JsonConvert.SerializeObject( info );

            //将该客户端的登录信息告诉其它客户端
            BroadcastMessage( msg );
        }

        //登陆
        void onClientLogin( Socket caller, MsgData msg )
        {

            //用户登陆
            var info = JsonConvert.DeserializeObject<UserInfo>( msg.data );
            var info_romote = users[info.ID];


            //刷新
            clients[info.ID] = caller;
            info_romote.name = info.name;
            info_romote.state = 2;
            msg.caller = info.ID;
            msg.data = JsonConvert.SerializeObject( info_romote );
            msg.type = MsgType.FriendEvent;
            //将该客户端的登录信息告诉其它客户端
            BroadcastMessage( msg );


            //好友列表
            var data = new login_success_result( );
            data.info = info_romote;
            if ( users.Count > 0 )
            {
                data.friends = new UserInfo[users.Count]; //世界的其他人信息
                users.Values.CopyTo( data.friends, 0 );
            }
            
            //离线信息
            List<chat_data> message = null;
            offLineInformation.TryGetValue( info.ID, out message );
            data.message = message;

            //发送好友列表信息
            var msg2 = new MsgData( );
            msg2.type = MsgType.Login;
            msg2.data = JsonConvert.SerializeObject( data );
            EasyServer.Send( caller, JsonConvert.SerializeObject( msg2 ) );
        }

        //客户端向另一个客户端发送消息
        void onClient2Client( Socket caller, MsgData msg )
        {

            Socket p = null;
            UserInfo user = null;

            foreach ( var k in msg.receiver )
            {

                if ( users.TryGetValue( k, out user ) )
                {

                    if ( user.state == 2 )
                    {
                        //即时消息
                        if ( clients.TryGetValue( k, out p ) )
                        {
                            EasyServer.Send( p, JsonConvert.SerializeObject( msg ) );
                        }
                    }
                    else
                    {
                        //离线消息
                        var chatContent = JsonConvert.DeserializeObject<chat_data>( msg.data );

                        offlineProc( k, chatContent );
                    }
                }

            }

        }
        //广播消息
        void BroadcastMessage( MsgData e )
        {
            //通知其它玩家 用户登录
            foreach ( var client in clients )
            {

                if ( client.Key != e.caller )
                {
                    EasyServer.Send( client.Value, JsonConvert.SerializeObject( e ) );
                }
            }
        }




        public string[] loadXmlConfig( string configFile )
        {
            //服务器的地址和开放端口
            string maxLinkCount = "100";
            string port = "5566";

            //首次创建配置文件
            if ( !File.Exists( configFile ) )
            {
                new XElement( "Config",
                  new XElement( "Server",
                    new XElement( "MaxLinkeCount", maxLinkCount ),
                    new XElement( "Port", port )
                   ) ).Save( configFile );
            }
            else
            {
                //读取ip配置
                try
                {
                    XElement xroot = XElement.Load( configFile );
                    maxLinkCount = xroot.Descendants( "Server" ).Select( xml => xml.Element( "MaxLinkeCount" ).Value ).ToArray( )[0];
                    port = xroot.Descendants( "Server" ).Select( xml => xml.Element( "Port" ).Value ).ToArray( )[0];

                }
                catch ( Exception ex )
                {
                    Console.WriteLine( $"unknown error: {ex.StackTrace}" );
                }
            }

            return new string[] { maxLinkCount, port };
        }

        public void Loop( )
        {
            while ( true )
            {
                //存档 命令相关

                //休眠200ms
                System.Threading.Thread.Sleep( 200 );
            }
        }
    }
}
